﻿using System;
using System.Linq.Expressions;

namespace Mg.ExpressionParser.Parser
{
    class BinaryExpressionParser : BaseExpressionParser<BinaryExpression>
    {
        private void OperatorParser(ExpressionType expressionNodeType, int operatorIndex, SqlPack sqlPack, bool useIs = false)
        {
            switch (expressionNodeType)
            {
                case ExpressionType.And:
                case ExpressionType.AndAlso:
                    sqlPack.Sql.Insert(operatorIndex, " AND");
                    break;
                case ExpressionType.Equal:
                    if (useIs)
                    {
                        sqlPack.Sql.Insert(operatorIndex, " IS");
                    }
                    else
                    {
                        sqlPack.Sql.Insert(operatorIndex, " =");
                    }
                    break;
                case ExpressionType.GreaterThan:
                    sqlPack.Sql.Insert(operatorIndex, " >");
                    break;
                case ExpressionType.GreaterThanOrEqual:
                    sqlPack.Sql.Insert(operatorIndex, " >=");
                    break;
                case ExpressionType.NotEqual:
                    if (useIs)
                    {
                        sqlPack.Sql.Insert(operatorIndex, " IS NOT");
                    }
                    else
                    {
                        sqlPack.Sql.Insert(operatorIndex, " <>");
                    }
                    break;
                case ExpressionType.Or:
                case ExpressionType.OrElse:
                    sqlPack.Sql.Insert(operatorIndex, " OR");
                    break;
                case ExpressionType.LessThan:
                    sqlPack.Sql.Insert(operatorIndex, " <");
                    break;
                case ExpressionType.LessThanOrEqual:
                    sqlPack.Sql.Insert(operatorIndex, " <=");
                    break;
                default:
                    throw new NotImplementedException("未实现的节点类型" + expressionNodeType);
            }
        }

        protected override SqlPack Join(BinaryExpression expression, SqlPack sqlPack)
        {
            ExpressionParserProvider.Join(expression.Left, sqlPack);
            int operatorIndex = sqlPack.Sql.Length;

            ExpressionParserProvider.Join(expression.Right, sqlPack);
            int sqlLength = sqlPack.Sql.Length;

            if (sqlLength - operatorIndex == 5 && sqlPack.ToString().EndsWith("NULL"))
            {
                OperatorParser(expression.NodeType, operatorIndex, sqlPack, true);
            }
            else
            {
                OperatorParser(expression.NodeType, operatorIndex, sqlPack);
            }

            return sqlPack;
        }

        protected override SqlPack Where(BinaryExpression expression, SqlPack sqlPack)
        {
            if(ExistsBracket(expression.Left))
            {
                sqlPack.Sql.Append(" (");
                ExpressionParserProvider.Where(expression.Left, sqlPack);
                sqlPack.Sql.Append(") ");
            }
            else
                ExpressionParserProvider.Where(expression.Left, sqlPack);

            int signIndex = sqlPack.Length;

            if (ExistsBracket(expression.Right))
            {
                sqlPack.Sql.Append(" (");
                ExpressionParserProvider.Where(expression.Right, sqlPack);
                sqlPack.Sql.Append(") ");
            }
            else
                ExpressionParserProvider.Where(expression.Right, sqlPack);
            int sqlLength = sqlPack.Length;

            if (sqlLength - signIndex == 5 && sqlPack.ToString().EndsWith("NULL"))
            {
                OperatorParser(expression.NodeType, signIndex, sqlPack, true);
            }
            else
            {
                OperatorParser(expression.NodeType, signIndex, sqlPack);
            }

            return sqlPack;
        }


        /// <summary> 判断是否需要添加括号
        /// </summary>
        private static bool ExistsBracket(Expression expr)
        {
            var s = expr.ToString();
            return s != null && s.Length > 5 && s[0] == '(' && s[1] == '(';
        }

    }
}
